package com.wl.api.service.business.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.wl.api.common.utils.BeanUtils;
import com.wl.api.common.utils.CollectionUtil;
import com.wl.api.common.utils.MessageCodeEnum;
import com.wl.api.common.utils.ObjectUtil;
import com.wl.api.common.utils.PageInfo;
import com.wl.api.common.utils.RWYException;
import com.wl.api.common.utils.StringUtil;
import com.wl.api.dto.business.CustomerAddrFromDTO;
import com.wl.api.dto.business.CustomerAddrReachDTO;
import com.wl.api.dto.business.CustomerOrderDTO;
import com.wl.api.dto.shipping.PickupLocationDTO;
import com.wl.api.dto.system.SecurityAreaLadderExtendDTO;
import com.wl.api.dto.system.SecurityChannelAreaLadderPriceDTO;
import com.wl.api.dto.system.SecurityChannelAreaServiceNetworkDTO;
import com.wl.api.dto.system.SecurityChannelAreaServicePartnerDTO;
import com.wl.api.dto.system.SecurityChannelDTO;
import com.wl.api.dto.system.SecurityChannelLadderPriceDTO;
import com.wl.api.mapper.business.CustomerOrderMapper;
import com.wl.api.model.business.CustomerFund;
import com.wl.api.model.business.CustomerOrder;
import com.wl.api.model.business.CustomerOrderDetail;
import com.wl.api.model.business.CustomerOrderServiceFee;
import com.wl.api.model.system.SecurityChannelAreaService;
import com.wl.api.model.system.SecurityChannelDomestic;
import com.wl.api.model.system.SecurityChannelDomesticLadderPrice;
import com.wl.api.service.business.ICustomerAddrFromService;
import com.wl.api.service.business.ICustomerAddrReachService;
import com.wl.api.service.business.ICustomerFundService;
import com.wl.api.service.business.ICustomerOrderDetailService;
import com.wl.api.service.business.ICustomerOrderService;
import com.wl.api.service.business.ICustomerOrderServiceFeeService;
import com.wl.api.service.system.ISecurityChannelAreaLadderPriceService;
import com.wl.api.service.system.ISecurityChannelAreaServiceNetworkService;
import com.wl.api.service.system.ISecurityChannelAreaServicePartnerService;
import com.wl.api.service.system.ISecurityChannelAreaServiceService;
import com.wl.api.service.system.ISecurityChannelService;
import static com.wl.api.common.utils.PageInfo.assemPaInfo;
/**
 *
 * CustomerOrder 表数据服务层接口实现类
 *
 */
@Service
public class CustomerOrderServiceImpl extends ServiceImpl<CustomerOrderMapper, CustomerOrder> implements ICustomerOrderService {
	@Autowired
	ICustomerFundService customerFundService;
	@Autowired
	ISecurityChannelService channelService;
	@Autowired
	ICustomerOrderDetailService orderDetailService;
	@Autowired
	CustomerOrderMapper customerOrderMapper;
	@Autowired
	ICustomerAddrFromService customerAddrFromService;
	@Autowired
	ICustomerAddrReachService customerAddrReachService;
	@Autowired
	ISecurityChannelAreaLadderPriceService channelAreaLadderPriceService;
	@Autowired
	ISecurityChannelAreaServiceNetworkService areaServiceNetworkService;
	@Autowired
	ISecurityChannelAreaServicePartnerService areaServicePartnerService;
	@Autowired
	ICustomerOrderServiceFeeService orderServiceFeeService;
	@Autowired
	ISecurityChannelAreaServiceService areaServiceService;
	
	@Transactional
	@Override
	public MessageCodeEnum createOrder(CustomerOrderDTO order) {
		//String result = "success";
		//订单状态 0:待付款,1:已付款,2:付款失败,3:申请退款,4:已退款
		Integer state = 1;
		String orderNo = StringUtil.getRandomDateID();
		boolean pass = true;
		CustomerFund fund = null;
		MessageCodeEnum result =  MessageCodeEnum.request_success;
		Assert.notNull(order.getCustId());
		BigDecimal amountPrice = new BigDecimal("0");
		// 国际物流费用
		BigDecimal foreign_channel_amt = new BigDecimal("0"), 
				//国内上门取件服务费
				pickup_service_amt =new BigDecimal("0"), 
				//国外派送费
				delivery_service_amt = new BigDecimal("0"), 
				//国内客户自送网点服务费
				fee_delivery_amt = new BigDecimal("0");
		//计算渠道费
		SecurityChannelDTO channel = channelService.getDetail(SecurityChannelDTO.builder().id(order.getChannelId()).build());
		if (Objects.isNull(channel)) { 
			return MessageCodeEnum.request_is_illegal;
		}
		Optional<SecurityChannelLadderPriceDTO> ladderPrice =  channel.getFeeLadderList().parallelStream().filter(s -> s.getWeightFrom().compareTo(order.getWeight()) <= 0 && s.getWeightTo().compareTo(order.getWeight())>=0).findFirst();
		if (!ladderPrice.isPresent()) {
			return MessageCodeEnum.request_out_of_shipping_range;
		}
		if (pass) {
			// 上浮后的渠道费用
			foreign_channel_amt = channel.getFloatRate().add(new BigDecimal("1")).multiply(ladderPrice.get().getAmount()).setScale(2,  BigDecimal.ROUND_HALF_DOWN);
			//查询服务费用(包含两种1.上门取件服务, 2:自送网点服务 )
			//SecurityAreaLadderExtendDTO serviceLadder = channelAreaLadderPriceService.getAreaLadderDetail(SecurityAreaLadderExtendDTO.builder().countryId(channel.getFromAreaId()).build());
			if (order.getNetworkId() != null) {
				fee_delivery_amt = getFeeServiceAmt(order);
			}
			if (order.getServicePickupId() != null) {
				pickup_service_amt = getFeeServiceAmt(order);
			}
			
			if (pickup_service_amt.compareTo(new BigDecimal("0")) <= 0 
					&& fee_delivery_amt.compareTo(new BigDecimal("0")) <= 0) {
			
				return MessageCodeEnum.request_out_of_shipping_range;
			}
			
			if (pass) {
				amountPrice = amountPrice.add(foreign_channel_amt).add(fee_delivery_amt).add(pickup_service_amt);
				
				if (amountPrice.compareTo(new BigDecimal("1")) <1) {
					return MessageCodeEnum.request_is_illegal;
				}
				
				//用户资金
				 fund = customerFundService.selectOne(new EntityWrapper<CustomerFund>(CustomerFund.builder().custId(order.getCustId()).build()));
				if (Objects.isNull(fund) || amountPrice.compareTo(fund.getCurrentAmount()) > 0) {
					result = MessageCodeEnum.insufficient_balance_in_your_amount;
					state = 0;
					pass = false;
				}
			}
		}
		
		//执行金额扣减, 创建订单
		//推送物流单稍后处理
		if (state ==1) {
			customerFundService.updateById(CustomerFund.builder().fundId(fund.getFundId()).currentAmount(fund.getCurrentAmount().subtract(amountPrice)).beforeAmount(fund.getCurrentAmount()).totalAmount(fund.getTotalAmount()).build());
			order.setPayAmt(amountPrice);
			order.setPaytime(new Date());
			order.setIspay(1);
		}
		//创建订单信息
		//设置应付金额
		order.setAmount(amountPrice);
		//国际物流费用
		order.setForeignShoppingFee(foreign_channel_amt);
		order.setLocalShoppingFee(pickup_service_amt);
		order.setLanFee(fee_delivery_amt);
		order.setRemark(state == 1? "支付订单成功": result.getMessage());
		
		CustomerOrder orderEnity = BeanUtils.copyProperties(order, CustomerOrder.class);
		insert(orderEnity.buildState(state).buildOrderNo(orderNo));
		orderDetailService.insertBatch(BeanUtils.copyProperties(order.getOrderDetials().parallelStream().map(s -> s.buildOrderID(orderEnity.getOrderId())).collect(Collectors.toList()), CustomerOrderDetail.class));
		order.setOrderId(orderEnity.getOrderId());
		insertOrUpdatetFeeService(order, pickup_service_amt.compareTo(new BigDecimal("0")) > 0 ? pickup_service_amt: fee_delivery_amt);
		order.setOrderNo(orderNo);
		return result;
	}
	
	
	private BigDecimal getFeeServiceAmt(CustomerOrderDTO param) {
		BigDecimal amt = new BigDecimal("0");
		Integer serviceId = 0;
		if (param.getNetworkId() != null) {
			SecurityChannelAreaServiceNetworkDTO netService = areaServiceNetworkService.getDetail(param.getNetworkId());
			if(Objects.isNull(netService) || CollectionUtils.isEmpty(netService.getLadderList())) {
				return amt;
			}
			
			Optional<SecurityChannelAreaLadderPriceDTO> ladder = netService.getLadderList().parallelStream().filter(s -> s.getWeightFrom().compareTo(param.getWeight()) <= 0 && s.getWeightTo().compareTo(param.getWeight())>=0).findFirst();
			if (ladder.isPresent()) {
				amt = amt.add(ladder.get().getAmount());
			}
			serviceId = netService.getServiceId();
		}
		if (param.getServicePickupId() != null) {
			SecurityChannelAreaServicePartnerDTO partnerService = areaServicePartnerService.getPartnerDetail(param.getServicePickupId());
			if(Objects.isNull(partnerService) || CollectionUtils.isEmpty(partnerService.getPickupLadderList())) {
				return amt;
			}
			
			Optional<SecurityChannelAreaLadderPriceDTO> ladder = partnerService.getPickupLadderList().parallelStream().filter(s -> s.getWeightFrom().compareTo(param.getWeight()) <= 0 && s.getWeightTo().compareTo(param.getWeight())>=0).findFirst();
			if (ladder.isPresent()) {
				amt = amt.add(ladder.get().getAmount());
			}
			serviceId = partnerService.getServiceId();
		}
		
		SecurityChannelAreaService areaService = areaServiceService.selectById(serviceId);
		param.setFeeType(areaService.getFeeType());
		return amt;
	}
	
	/**
	 *  插入或更新订单服务费
	 * @param param
	 */
	private BigDecimal insertOrUpdatetFeeService(CustomerOrderDTO param, BigDecimal amt) {
		
		//更新或删除服务费数据
		if(Objects.nonNull(param.getOrderId())) {
			orderServiceFeeService.delete(new EntityWrapper<CustomerOrderServiceFee>().where("order_id={0}", param.getOrderId()));
			orderServiceFeeService.insert(CustomerOrderServiceFee.builder().areaServiceId(param.getNetworkId() != null? param.getNetworkId()
					: param.getServicePickupId()).feeAmount(amt).feeType(param.getFeeType()).orderId(param.getOrderId()).build());
		} else {
			orderServiceFeeService.insert(CustomerOrderServiceFee.builder().areaServiceId(param.getNetworkId() != null? param.getNetworkId()
					: param.getServicePickupId()).feeAmount(amt).feeType(param.getFeeType()).orderId(param.getOrderId()).build());
		}
		
		return amt;
	}
	
	
	@Transactional
	@Override
	public MessageCodeEnum updateOrder(CustomerOrderDTO order) throws Exception {
		Assert.notNull(order);
		Assert.notNull(order.getOrderNo());
		boolean pass = true;
		MessageCodeEnum result =  MessageCodeEnum.request_success;
		Wrapper<CustomerOrder> wrapper = new EntityWrapper<CustomerOrder>().where(" 1=1 ");
		if (order.getCustId() != null) {
			wrapper.andNew("cust_id", order.getCustId());
		}
		wrapper.andNew("order_no", order.getOrderNo());
		
		CustomerOrder customerOrder = selectOne(wrapper);
		Assert.notNull(customerOrder);
		order.setOrderId(customerOrder.getOrderId());
		BigDecimal amountPrice = new BigDecimal("0");
		// 国际物流费用
		BigDecimal foreign_channel_amt = new BigDecimal("0"), 
				//国内上门取件服务费
				pickup_service_amt =new BigDecimal("0"), 
				//国外派送费
				delivery_service_amt = new BigDecimal("0"), 
				//国内客户自送网点服务费
				fee_delivery_amt = new BigDecimal("0");
		
	
		//客户端继续支付订单
		if(order.getUpdateType() != null && order.getUpdateType() == 1) {
			CustomerFund fund = null;
			if (customerOrder.getState() != 0 && customerOrder.getState() != 2) {
				throw RWYException.create(403, "订单状态有误");
			}
			
			//订单状态 0:待付款,1:已付款,2:付款失败,3:申请退款,4:已退款
			Integer state = 1;
			
			Assert.notNull(order.getCustId());
		
			
			//目前先计算渠道费用,其他不清楚
			SecurityChannelDTO channel = channelService.getDetail(SecurityChannelDTO.builder().id(order.getChannelId()).build());
			if (Objects.isNull(channel)) { 
				return MessageCodeEnum.request_is_illegal;
			}
			Optional<SecurityChannelLadderPriceDTO> ladderPrice =  channel.getFeeLadderList().parallelStream().filter(s -> s.getWeightFrom().compareTo(order.getWeight()) <= 0 && s.getWeightTo().compareTo(order.getWeight())>=0).findFirst();
			if (!ladderPrice.isPresent()) {
				return MessageCodeEnum.request_out_of_shipping_range;
				
			}
		
			//国际物流费用
			foreign_channel_amt = channel.getFloatRate().add(new BigDecimal("1")).multiply(ladderPrice.get().getAmount()).setScale(2,  BigDecimal.ROUND_HALF_DOWN);
			if (amountPrice.compareTo(new BigDecimal("1")) <1) {
				return MessageCodeEnum.request_is_illegal;
			
			}
			
			//查询服务费用(包含两种1.上门取件服务, 2:自送网点服务 )
			if (order.getNetworkId() != null) {
				fee_delivery_amt = getFeeServiceAmt(order);
			}
			if (order.getServicePickupId() != null) {
				pickup_service_amt = getFeeServiceAmt(order);
			}
			
			if (pickup_service_amt.compareTo(new BigDecimal("0")) <= 0 
					&& fee_delivery_amt.compareTo(new BigDecimal("0")) <= 0) {
				return MessageCodeEnum.request_out_of_shipping_range;
				
			}
			if (pass) {
				amountPrice = amountPrice.add(foreign_channel_amt).add(fee_delivery_amt).add(pickup_service_amt);
				
				fund = customerFundService.selectOne(new EntityWrapper<CustomerFund>(CustomerFund.builder().custId(order.getCustId()).build()));
				if (Objects.isNull(fund) || amountPrice.compareTo(fund.getCurrentAmount()) > 0) {
					result =  MessageCodeEnum.insufficient_balance_in_your_amount;
					state = 2;
					pass =false;
				}
				
				List<CustomerOrderDetail> detailSource = orderDetailService.selectList(new EntityWrapper<CustomerOrderDetail>().where("order_id={0}", customerOrder.getOrderId()));
				List<CustomerOrderDetail> updateList = order.getOrderDetials().parallelStream().filter(s -> !ObjectUtil.isEmpty(s.getOrderDetailId())).map(s -> BeanUtils.copyProperties(s, CustomerOrderDetail.class)).collect(Collectors.toList()); 
				List<CustomerOrderDetail> insertList = order.getOrderDetials().parallelStream().filter(s -> ObjectUtil.isEmpty(s.getOrderDetailId())).map(s -> BeanUtils.copyProperties(s, CustomerOrderDetail.class)).collect(Collectors.toList());
				
				List<Long> ids = detailSource.parallelStream().map(CustomerOrderDetail::getOrderDetailId).collect(Collectors.toList());
				List<Long> delIds = new ArrayList<>();
				//del 
				if (!CollectionUtil.isEmpty(detailSource)) {
					for(CustomerOrderDetail sc: detailSource) {
						if (CollectionUtil.isEmpty(updateList)) {
							delIds.add(sc.getOrderDetailId());
							continue;
						}
						if (updateList.parallelStream().noneMatch(s -> Objects.equals(s.getOrderDetailId(), sc.getOrderDetailId()))) {
							delIds.add(sc.getOrderDetailId());
							continue;
						}
					}
				}
				
				if(!CollectionUtil.isEmpty(delIds)) {
					orderDetailService.deleteBatchIds(delIds);
				}
				if (!CollectionUtil.isEmpty(updateList)) {
					orderDetailService.updateBatchById(updateList.parallelStream().filter(s -> ids.contains(s.getOrderDetailId())).collect(Collectors.toList()));
				}
				if (!CollectionUtil.isEmpty(insertList)) {
					orderDetailService.insertBatch(insertList);
				}
				
				//更新支付金额处理
				//推送物流单稍后处理
				if (state == 1) {
					customerFundService.updateById(CustomerFund.builder().fundId(fund.getFundId()).currentAmount(fund.getCurrentAmount().subtract(amountPrice)).beforeAmount(fund.getCurrentAmount()).totalAmount(fund.getTotalAmount()).build());
					order.setPayAmt(amountPrice);
					order.setPaytime(new Date());
					order.setIspay(1);
				}
				//创建订单信息
				//设置应付金额
				order.setAmount(amountPrice);
				//国际物流费用
				order.setForeignShoppingFee(foreign_channel_amt);
				order.setLocalShoppingFee(pickup_service_amt);
				order.setLanFee(fee_delivery_amt);
				order.setRemark(state == 1? "支付订单成功": result.getMessage());
				order.setState(state);
				insertOrUpdatetFeeService(order, pickup_service_amt.compareTo(new BigDecimal("0")) > 0 ? pickup_service_amt: fee_delivery_amt);
			}
			
			
		}
		//订单信息
		CustomerOrder orderEnity = BeanUtils.copyProperties(order, CustomerOrder.class);
		updateById(orderEnity.buildOrderId(customerOrder.getOrderId()));
		return result;
	}
	
	@Override
	public PageInfo<CustomerOrderDTO> queryOrderPage(CustomerOrderDTO order) {
		int count = customerOrderMapper.selectCustomerOrderItemCount(order);
		List<CustomerOrderDTO> list = customerOrderMapper.selectCustomerOrderItem(order);
	
		return assemPaInfo(order.getPage(), count, order.getPageSize(), list);
	}

	@Override
	public CustomerOrderDTO getOrderDetail(CustomerOrderDTO param) {
		CustomerOrder order = selectOne(new EntityWrapper<CustomerOrder>(BeanUtils.copyProperties(param, CustomerOrder.class)));
		CustomerOrderDTO result = BeanUtils.copyProperties(order, CustomerOrderDTO.class);
		if (!Objects.isNull(result)) {
			result.buildAddFrom(BeanUtils.copyProperties(customerAddrFromService.selectById(order.getFromId()), CustomerAddrFromDTO.class))
				  .buildAddReach(BeanUtils.copyProperties(customerAddrReachService.selectById(order.getReachId()), CustomerAddrReachDTO.class))
			      .buildOrderDetail(orderDetailService.getOrderDetailList(order.getOrderId()));
		}
		return result;
	}

	


}